package com.studio5704website.api.security;

import com.studio5704website.core.service.JwtService;
import com.studio5704website.core.user.RoleWithTokenService;
import com.studio5704website.core.user.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;
import java.util.Optional;

/**
 * @author 高威
 * 过滤器，用于解析token, 得到用户信息, 并且把Authentication添加到Spring Security里
 */
public class JwtTokenFilter extends OncePerRequestFilter {

    @Autowired
    @Qualifier("cusJwtService")
    private JwtService jwtService;

    @Autowired
    private UserRepository userRepository;

    @Autowired
    @Qualifier("redisRoleWithTokenService")
    private RoleWithTokenService roleWithTokenService;

    private String header = "Authorization";

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        getTokenString(request.getHeader(header)).ifPresent(token -> {
            jwtService.getSubFromToken(token).ifPresent(id -> {
                if (SecurityContextHolder.getContext().getAuthentication() == null) {
                    // 这里采用从redis里查token, redis自动同步所有token。实现多端共享登录信息
                    roleWithTokenService.getRoleWithToken(id).ifPresent( roleWithToken -> {
                        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
                                roleWithToken,
                                null,
                                Collections.emptyList()
                        );
                       authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
                    });
                }
            });
        });
        filterChain.doFilter(request, response);
    }

    private Optional<String> getTokenString(String header) {
        if (header == null) {
            return Optional.empty();
        } else {
            return Optional.ofNullable(header);
        }
    }
}
